﻿#region

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using NetBay.Core.BusinessEntities;
using Rio.Applications.Web.Services;
using Rio.Framework.Localisation;
using Telerik.Windows.Controls;
using WindowStartupLocation = Telerik.Windows.Controls.WindowStartupLocation;

#endregion

namespace Rio.Framework.Pages.ChildWindows
{
    public partial class FilterWindow
    {
        #region Enums

        public enum SelectedMode
        {
            Single,
            Multiple
        }

        #endregion

        #region Readonly & Static Fields

        private readonly Index _currentIndex;
        private readonly Dictionary<long, string> _dicIndexValues;
        private readonly long _folderTypeId;
        private readonly long _organizationId;
        private readonly SelectedMode _selectedMode;

        #endregion

        #region Fields

        private bool _IsFilterValuesLoaded;
        private bool _IsValuesLoaded;

        #endregion

        #region Constructors

        /// <summary>
        /// Create instance of the window
        /// </summary>
        /// <param name="p_oIndex">Instance of <see cref="Index" /></param>
        /// <param name="p_lOrganisationId">Organization identifier</param>
        /// <param name="p_lForlderTypeId">FolderType identifier</param>
        /// <param name="p_oDicIndexValues">Dictionary of index identifier-value</param>
        /// <param name="P_oSelectedMode">Selection mode</param>
        /// <param name="FilteredByDefault">if set to <c>true</c> [filtered by default].</param>
        public FilterWindow(Index p_oIndex, long p_lOrganisationId, long p_lForlderTypeId, Dictionary<long, string> p_oDicIndexValues, SelectedMode P_oSelectedMode = SelectedMode.Single,
                            bool FilteredByDefault = true)
        {
            InitializeComponent();
            InitLabel();

            //Init values list
            _selectedMode = P_oSelectedMode;
            _currentIndex = p_oIndex;
            _organizationId = p_lOrganisationId;
            _folderTypeId = p_lForlderTypeId;

            _dicIndexValues = p_oDicIndexValues;
            if (p_oIndex.Type == (int) IndexDomainServiceEnums.IndexType.String)
            {
                Dictionary<long, string> l_oReplaceDic = new Dictionary<long, string>();
                foreach (var pair in p_oDicIndexValues)
                {
                    if (pair.Key == p_oIndex.Indentifier)
                    {
                        l_oReplaceDic.Add(pair.Key, pair.Value.EndsWith("%") ? pair.Value : pair.Value + "%");
                    }
                    else
                    {
                        l_oReplaceDic.Add(pair.Key, pair.Value);
                    }
                }
                _dicIndexValues = l_oReplaceDic;
            }


            //Fill list of values
            IsEnabled = false;
            checkboxFilter.Visibility = Visibility.Visible;
            checkboxFilter.IsChecked = FilteredByDefault;
            if (checkboxFilter.IsChecked == false)
                LoadIndexWithoutFilterQuery();

            CanMove = true;
            ResizeMode = ResizeMode.NoResize;
            WindowStartupLocation = WindowStartupLocation.CenterScreen;
        }

        #endregion

        #region Instance Properties

        /// <summary>
        ///   all values list
        /// </summary>
        public List<string> m_lszListValuesInput { get; set; }

        /// <summary>
        ///   Values list with filter
        /// </summary>
        public List<string> m_lszListValuesInputWithFilter { get; set; }

        /// <summary>
        /// </summary>
        public string m_szSelectedItem { get; set; }

        /// <summary>
        /// </summary>
        public List<string> m_szSelectedItems { get; set; }

        #endregion

        #region Instance Methods

        /// <summary>
        ///   Translation
        /// </summary>
        public void InitLabel()
        {
            checkboxFilter.Content = Resx.GetLabel(Constantes.k_WITH_FILTER);
            buttonOk.Content = Resx.GetLabel(Constantes.k_OK);
            buttonCancel.Content = Resx.GetLabel(Constantes.k_CANCEL);
            LabelContains.Text = string.Format("{0}:", Resx.GetLabel(Constantes.k_STARTING_WITH));
        }

        /// <summary>
        ///   Cleans the date filter.
        /// </summary>
        /// <param name="P_oListValueFilter"> The p_o list value filter. </param>
        /// <returns> </returns>
        private List<string> CleanDateFilter(IEnumerable<string> P_oListValueFilter)
        {
            List<DateTime> liste = new List<DateTime>();
            if (P_oListValueFilter != null)
            {
                liste.AddRange(P_oListValueFilter.Select(DateTime.Parse));
            }
            liste.Sort((x, y) => y.CompareTo(x));
            return liste.Select(p => p.ToShortDateString()).ToList();
        }

        /// <summary>
        ///   Cleans the double filter.
        /// </summary>
        /// <param name="P_oListValueFilter"> The p_o list value filter. </param>
        /// <returns> </returns>
        private List<string> CleanDoubleFilter(IEnumerable<string> P_oListValueFilter)
        {
            List<double> liste = new List<double>();
            if (P_oListValueFilter != null)
            {
                liste.AddRange(P_oListValueFilter.Select(double.Parse));
            }
            liste.Sort((x, y) => y.CompareTo(x));
            return liste.Select(p => p.ToString()).ToList();
        }

        /// <summary>
        ///   Cleans the integer filter.
        /// </summary>
        /// <param name="P_oListValueFilter"> The p_o list value filter. </param>
        /// <returns> </returns>
        private List<string> CleanIntegerFilter(IEnumerable<string> P_oListValueFilter)
        {
            List<Int32> liste = new List<Int32>();
            if (P_oListValueFilter != null)
            {
                liste.AddRange(P_oListValueFilter.Select(int.Parse));
            }
            liste.Sort((x, y) => y.CompareTo(x));
            return liste.Select(p => p.ToString()).ToList();
        }

        /// <summary>
        /// </summary>
        /// <param name="P_oListValueFilter"> </param>
        /// <returns> </returns>
        private List<string> CleanUserFilter(IEnumerable<string> P_oListValueFilter)
        {
            List<string> L_oListValueFilter = new List<string>();
            string[] L_oTabString;
            if (P_oListValueFilter != null)
            {
                foreach (string str in P_oListValueFilter)
                {
                    L_oTabString = str.Split(new[] {';'});
                    if (L_oTabString.Length > 0)
                    {
                        L_oListValueFilter.Add(L_oTabString[1]);
                    }
                }
            }

            return L_oListValueFilter;
        }

        /// <summary>
        ///   For every value from ListValues, we have "VALUE;ID" for value list type index and user list type index, and we have "VALUE" for the other index type because for value list type index and user list type index we need the value to display and id to identify the value (for the consultation screen for exemple, to select the item in the combobox) here we need only the value So this function enable to parse the filter Value ("Value;Id") to return only a list of value
        /// </summary>
        /// <param name="P_oListValueFilter"> </param>
        /// <returns> </returns>
        private List<string> CleanValueFilter(IEnumerable<string> P_oListValueFilter)
        {
            List<string> L_oListValueFilter = new List<string>();
            string[] L_oTabString;
            if (P_oListValueFilter != null)
            {
                foreach (string str in P_oListValueFilter)
                {
                    L_oTabString = str.Split(new[] {';'});
                    if (L_oTabString.Length > 0)
                    {
                        L_oListValueFilter.Add(L_oTabString[0]);
                    }
                }
            }

            return L_oListValueFilter;
        }

        /// <summary>
        ///   This method is called to filter listbox values with a "starting with" constraint
        /// </summary>
        /// <param name="FilterTerm"> </param>
        /// <returns> </returns>
        private IEnumerable<string> FilterItems(string FilterTerm)
        {
            IEnumerable<string> result = null;
            if (checkboxFilter.IsChecked == true)
            {
                result = m_lszListValuesInputWithFilter;
            }
            else
            {
                result = m_lszListValuesInput;
            }

            if (!string.IsNullOrEmpty(FilterTerm) && result != null)
            {
                result = result.Where(f => f.ToString().ToLower().Contains(FilterTerm.ToLower()));
            }

            return result;
        }

        /// <summary>
        ///   Load index values without filter
        /// </summary>
        private void LoadIndexWithFilterQuery()
        {
            if (!_IsFilterValuesLoaded)
            {
                _IsFilterValuesLoaded = true;
                BusinessEntitiesDomainContext l_oBEDomainContext = new BusinessEntitiesDomainContext();
                var query = l_oBEDomainContext.GetIndexValuesByFolderTypeIdQuery(
                    _organizationId,
                    _folderTypeId,
                    _dicIndexValues
                    );
                IsEnabled = false;
                l_oBEDomainContext.Load(query, OnUpdateGetIndexValuesByFolderIdQueryCallbackFiltered, null);
            }
        }

        /// <summary>
        ///   Load index values with filter
        /// </summary>
        private void LoadIndexWithoutFilterQuery()
        {
            if (!_IsValuesLoaded)
            {
                _IsValuesLoaded = true;
                BusinessEntitiesDomainContext l_oBEDomainContext = new BusinessEntitiesDomainContext();
                Dictionary<long, string> l_oDico = new Dictionary<long, string>();
                if (!string.IsNullOrEmpty(_dicIndexValues[_currentIndex.Indentifier]))
                {
                    l_oDico.Add(_currentIndex.Indentifier, _dicIndexValues[_currentIndex.Indentifier]);
                }
                var query = l_oBEDomainContext.GetIndexValuesByFolderTypeIdQuery(
                    _organizationId,
                    _folderTypeId,
                    l_oDico
                    );
                IsEnabled = false;
                l_oBEDomainContext.Load(query, OnUpdateGetIndexValuesByFolderIdQueryCallbackWithoutFilter, null);
            }
        }

        /// <summary>
        ///   Fill a list of all values WITH filtering
        /// </summary>
        /// <param name="result"> </param>
        private void OnUpdateGetIndexValuesByFolderIdQueryCallbackFiltered(LoadOperation<OccurenciesByFolderType> result)
        {
            try
            {
                Dictionary<long, List<string>> L_oFolderControlValueWithFilter = new Dictionary<long, List<string>>();

                List<OccurenciesByFolderType> L_oFilterValues = new List<OccurenciesByFolderType>(result.Entities);
                if (L_oFilterValues.Count > 0)
                {
                    OccurenciesByFolderType l_oOccurencie = L_oFilterValues.First();

                    if (l_oOccurencie.IsValid)
                    {
                        OccurenciesForAllIndex l_oWithFilter = l_oOccurencie.WithFilter;
                        if ((l_oWithFilter != null) && (l_oWithFilter.OccurenciesList != null))
                        {
                            List<OccurenciesForOneIndex> L_oOccurenciesWithFilter = new List<OccurenciesForOneIndex>(l_oWithFilter.OccurenciesList);
                            foreach (OccurenciesForOneIndex item in L_oOccurenciesWithFilter)
                            {
                                L_oFolderControlValueWithFilter.Add(item.IndexId, new List<string>(item.OccurenciesList));
                            }
                        }
                    }
                }

                List<string> L_oListControlValueWithFilter;
                L_oFolderControlValueWithFilter.TryGetValue(_currentIndex.Indentifier, out L_oListControlValueWithFilter);

                // Call cleanValue for a list Users, ListOfValues, TypeFlow, 
                // Date: Convert to short date 
                switch (_currentIndex.Type)
                {
                    case (int) IndexDomainServiceEnums.IndexType.Users:
                        L_oListControlValueWithFilter = CleanUserFilter(L_oListControlValueWithFilter);
                        if (L_oListControlValueWithFilter != null && L_oListControlValueWithFilter.Count > 0)
                            L_oListControlValueWithFilter.Sort();
                        break;
                    case (int) IndexDomainServiceEnums.IndexType.ListOfValues:
                    case (int) IndexDomainServiceEnums.IndexType.TypeFlow:
                        L_oListControlValueWithFilter = CleanValueFilter(L_oListControlValueWithFilter);
                        if (L_oListControlValueWithFilter != null && L_oListControlValueWithFilter.Count > 0)
                            L_oListControlValueWithFilter.Sort();
                        break;
                    case (int) IndexDomainServiceEnums.IndexType.Date:
                        L_oListControlValueWithFilter = CleanDateFilter(L_oListControlValueWithFilter);
                        L_oListControlValueWithFilter.Reverse();
                        break;
                    case (int) IndexDomainServiceEnums.IndexType.Integer:
                    case (int) IndexDomainServiceEnums.IndexType.IntegerString:
                        L_oListControlValueWithFilter = CleanIntegerFilter(L_oListControlValueWithFilter);
                        L_oListControlValueWithFilter.Reverse();
                        break;

                    case (int)IndexDomainServiceEnums.IndexType.Double:
                        L_oListControlValueWithFilter = CleanDoubleFilter(L_oListControlValueWithFilter);
                        L_oListControlValueWithFilter.Reverse();
                        break;
                    default:
                        if (L_oListControlValueWithFilter != null && L_oListControlValueWithFilter.Count > 0)
                            L_oListControlValueWithFilter.Sort();
                        break;
                }
                m_lszListValuesInputWithFilter = L_oListControlValueWithFilter;

                if (m_lszListValuesInputWithFilter != null && m_lszListValuesInputWithFilter.Count > 0)
                {
                    listboxValues.ItemsSource = m_lszListValuesInputWithFilter;
                }
                else
                {
                    checkboxFilter.IsChecked = false;
                    checkboxFilter.IsEnabled = false;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("OnUpdateGetIndexValuesByFolderIdQueryCallbackFiltered error " + ex.Message);
            }
            finally
            {
                IsEnabled = true;
            }
        }

        /// <summary>
        ///   Fill a list of all values WITHOUT filtering
        /// </summary>
        /// <param name="result"> </param>
        private void OnUpdateGetIndexValuesByFolderIdQueryCallbackWithoutFilter(LoadOperation<OccurenciesByFolderType> result)
        {
            try
            {
                Dictionary<long, List<string>> L_oFolderControlValueWithOutFilter = new Dictionary<long, List<string>>();
                List<OccurenciesByFolderType> L_oFilterValues = new List<OccurenciesByFolderType>(result.Entities);
                if (L_oFilterValues.Count > 0)
                {
                    OccurenciesByFolderType l_oOccurencie = L_oFilterValues.First();

                    if (l_oOccurencie.IsValid)
                    {
                        OccurenciesForAllIndex l_oWithOutFilter = l_oOccurencie.WithoutFilter;
                        if ((l_oWithOutFilter != null) && (l_oWithOutFilter.OccurenciesList != null))
                        {
                            List<OccurenciesForOneIndex> L_oOccurenciesWithOutFilter = new List<OccurenciesForOneIndex>(l_oWithOutFilter.OccurenciesList);
                            foreach (OccurenciesForOneIndex item in L_oOccurenciesWithOutFilter)
                            {
                                L_oFolderControlValueWithOutFilter.Add(item.IndexId, new List<string>(item.OccurenciesList));
                            }
                        }
                    }
                }

                List<string> L_oListControlValueWithOutFilter;
                L_oFolderControlValueWithOutFilter.TryGetValue(_currentIndex.Indentifier, out L_oListControlValueWithOutFilter);

                // Call cleanValue for a list Users, ListOfValues, TypeFlow, 
                // Date: Convert to short date 
                switch (_currentIndex.Type)
                {
                    case (int) IndexDomainServiceEnums.IndexType.Users:
                        L_oListControlValueWithOutFilter = CleanUserFilter(L_oListControlValueWithOutFilter);
                        if (L_oListControlValueWithOutFilter != null)
                            L_oListControlValueWithOutFilter.Sort();
                        break;
                    case (int) IndexDomainServiceEnums.IndexType.ListOfValues:
                    case (int) IndexDomainServiceEnums.IndexType.TypeFlow:
                        L_oListControlValueWithOutFilter = CleanValueFilter(L_oListControlValueWithOutFilter);
                        if (L_oListControlValueWithOutFilter != null)
                            L_oListControlValueWithOutFilter.Sort();
                        break;
                    case (int) IndexDomainServiceEnums.IndexType.Date:
                        L_oListControlValueWithOutFilter = CleanDateFilter(L_oListControlValueWithOutFilter);
                        L_oListControlValueWithOutFilter.Reverse();
                        break;
                    case (int) IndexDomainServiceEnums.IndexType.Integer:
                    case (int) IndexDomainServiceEnums.IndexType.IntegerString:
                        L_oListControlValueWithOutFilter = CleanIntegerFilter(L_oListControlValueWithOutFilter);
                        L_oListControlValueWithOutFilter.Reverse();
                        break;

                    case (int)IndexDomainServiceEnums.IndexType.Double:
                        L_oListControlValueWithOutFilter = CleanDoubleFilter(L_oListControlValueWithOutFilter);
                        L_oListControlValueWithOutFilter.Reverse();
                        break;
                    default:
                        if (L_oListControlValueWithOutFilter != null)
                            L_oListControlValueWithOutFilter.Sort();
                        break;
                }

                m_lszListValuesInput = L_oListControlValueWithOutFilter;
                listboxValues.ItemsSource = m_lszListValuesInput;
            }
            catch (Exception ex)
            {
                MessageBox.Show("OnUpdateGetIndexValuesByFolderIdQueryCallbackWithoutFilter error " + ex.Message);
            }
            finally
            {
                IsEnabled = true;
            }
        }

        #endregion

        #region Event Handling

        private void ChildWindow_Closed(object sender, EventArgs e)
        {
        }

        /// <summary>
        ///   Filter value
        /// </summary>
        /// <param name="sender"> </param>
        /// <param name="e"> </param>
        private void ContainFilter_TextChanged(object sender, TextChangedEventArgs e)
        {
            listboxValues.ItemsSource = FilterItems(ContainFilter.Text);
        }

        /// <summary>
        ///   Click on listbox's item If it's a double click, we raise an event: "itemSelected"
        /// </summary>
        /// <param name="sender"> </param>
        /// <param name="e"> </param>
        private void Item_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 2)
            {
                if (listboxValues.SelectedItem != null)
                {
                    m_szSelectedItem = (string) listboxValues.SelectedItem;
                    DialogResult = true;
                    Close();
                }
            }
        }

        /// <summary>
        ///   Close the window
        /// </summary>
        /// <param name="sender"> </param>
        /// <param name="e"> </param>
        private void buttonCancel_Click(object sender, RoutedEventArgs e)
        {
            m_szSelectedItem = null;
            DialogResult = true;
            Close();
        }

        /// <summary>
        ///   Set selection and close this
        /// </summary>
        /// <param name="sender"> </param>
        /// <param name="e"> </param>
        private void buttonOk_Click(object sender, RoutedEventArgs e)
        {
            switch (_selectedMode)
            {
                case SelectedMode.Single:
                    m_szSelectedItem = (string) listboxValues.SelectedItem;
                    break;
                case SelectedMode.Multiple:
                    m_szSelectedItems = (List<string>) listboxValues.SelectedItems;
                    break;
            }

            if ((!String.IsNullOrEmpty(m_szSelectedItem)) ||
                (m_szSelectedItems != null && m_szSelectedItems.Count > 0))
            {
                DialogResult = true;
            }
            else
            {
                DialogResult = false;
            }
            Close();
        }

        /// <summary>
        ///   Display list filtered
        /// </summary>
        /// <param name="sender"> </param>
        /// <param name="e"> </param>
        private void checkboxFilter_Checked(object sender, RoutedEventArgs e)
        {
            LoadIndexWithFilterQuery();
            listboxValues.ItemsSource = m_lszListValuesInputWithFilter;
            ContainFilter.Text = string.Empty;
        }

        /// <summary>
        ///   Display list with no filter
        /// </summary>
        /// <param name="sender"> </param>
        /// <param name="e"> </param>
        private void checkboxFilter_Unchecked(object sender, RoutedEventArgs e)
        {
            LoadIndexWithoutFilterQuery();
            listboxValues.ItemsSource = m_lszListValuesInput;
            ContainFilter.Text = string.Empty;
        }

        #endregion
    }
}